// main.go
package main

import (
	"code.google.com/p/gochess/movement"
	"code.google.com/p/gochess/notation/fen"
	"code.google.com/p/gochess/notation/san"
	pos "code.google.com/p/gochess/position"
	"code.google.com/p/gochess/search"
	stats "code.google.com/p/gochess/statistics"
	"code.google.com/p/gochess/ui/text"
	"code.google.com/p/gochess/ui/uci"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"runtime/pprof"
)

func showUsage() {
	fmt.Fprintf(os.Stderr, "usage: gochess -uci -ucilog -d n -t n [-w] [-b] [-tablesize n] [-stats] [-log path] [-cpuprofile filename] [-memprofile filename] [-fen notation]\n")
	flag.PrintDefaults()
}

// see http://en.wikipedia.org/wiki/Glossary_of_chess to get the names right
func main() {

	// for uci ui
	uciMode := flag.Bool("uci", false, "enter uci mode")
	uciLog := flag.Bool("ucilog", false, "log messages in uci mode to stderr")

	// for text ui
	searchDepth := flag.Uint("d", 0, "search depth")
	timeForMove := flag.Duration("t", 0, "time for one move; examples: 200ms, 10s, 1h10m, 1.5h")
	fenPosition := flag.String("fen", fen.InitialPosition, "Fen of position to play")
	computerIsWhite := flag.Bool("w", false, "computer plays White")
	computerIsBlack := flag.Bool("b", false, "computer plays Black")
	ttSizeMB := flag.Uint("tablesize", search.TTDefaultSize, "size (in MB) of the transposition table (will be rounded down to a power of 2)")
	showStatistics := flag.Bool("stats", false, "show statistics for computer moves")
	logFile := flag.String("log", "/tmp/search", "file to write logging data")
	usage := flag.Bool("h", false, "show usage information")

	// for profiling with pprof
	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile := flag.String("memprofile", "", "write memory profile to this file")

	flag.Usage = showUsage
	flag.Parse()

	if flag.NFlag() < 1 || *usage {
		showUsage()
		os.Exit(2)
	}

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Printf("Could not create file %s.\n", *cpuprofile)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *uciMode {
		w := ioutil.Discard
		if *uciLog {
			w = os.Stderr
		}
		uci.StartEngine(os.Stdin, os.Stdout, w)
		return
	}

	if *timeForMove == 0 && *searchDepth == 0 {
		showUsage()
		os.Exit(2)
	}

	searchFlags := search.PrintPV

	white, black := HumanPlayer, HumanPlayer
	if *computerIsWhite {
		white = ComputerPlayer
	}
	if *computerIsBlack {
		black = ComputerPlayer
	}

	p, err := fen.Parse(*fenPosition)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error while parsing FEN: %v\n", err.Error())
		os.Exit(1)
	}

	search.SetLogFile(*logFile)
	search.Transpositions.Resize(int(*ttSizeMB))
	g := NewGame(p, white, black)

	for {
		stm := g.position.SideToMove()
		fmt.Print(pos.Render(p))
		fmt.Print(fen.Sprint(g.position), "\n\n")
		switch g.Status() {
		case Stalemate:
			fmt.Println("Stalemate. Game result: Draw.")
			break
		case Checkmate:
			fmt.Printf("Checkmate. Game result: %s wins.\n", pos.Opponent(stm))
			break
		}
		moveOptions := movement.GenerateLegalMoves(g.position)
		if g.Player(stm) == HumanPlayer {
			if exit, move := text.ReadMoveFromUser(g.position, moveOptions); !exit {
				pos.MakeMove(g.position, move)
				continue
			}
			break
		} else {
			if *showStatistics {
				stats.StartTimer()
			}
			// search.Transpositions.Clear()
			move, _ := search.Run(g.position, pos.NoMove, *timeForMove,
				int32(*searchDepth), searchFlags)
			fmt.Printf("\nComputers Move: %s\n", san.SprintMove(g.position, move, moveOptions))
			if *showStatistics {
				stats.StopTimer()
				stats.PrintStatistics()
			}
			pos.MakeMove(g.position, move)
		}
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			fmt.Printf("could not create file %s\n", *cpuprofile)
			os.Exit(1)
		}
		pprof.WriteHeapProfile(f)
		f.Close()
	}
}
